const isObject = val => val !==null && typeof val === 'object'

const convert = target => isObject(target) ? reactive(target) : target
const hasOwnproperty = Object.prototype.hasOwnProperty;
const hasOwn = (target, key) => hasOwnproperty.call(target, key)
export function reactive (target) {
    if (!isObject(target)) return target;
    const handler = {
        get (target, key, receiver) {
            //收集依赖
            console.log('get', key)
            track(target, key)
            const result = Reflect.get(target, key, receiver);
            return convert(result)
        },
        set (target, key, value, receiver) {
            let result = true;
            const oldValue = Reflect.get(target, key, receiver)
            if (oldValue !== value) {
                result = Reflect.set(target, key, value, receiver)
                //触发更新
                trigger(target, key)
                console.log('set', key, value)
            }
            return result
        },
        deleteProperty(target, key) {
            const haskey = hasOwn(target, key)
            const result = Reflect.deleteProperty(target, key)
            if (haskey && result) {
                //触发更新
                trigger(target, key)
                console.log('delete', key)
            }
            return result
        }
    }

    return new Proxy(target, handler);
}
let activeEffect = null; //当前活动的函数
export function effect(callback) {
    activeEffect = callback; 
    callback() //此时会访问响应式对象的属性，需要收集依赖
    activeEffect = null;
}
let targetMap = new WeakMap()

export function track(target, key) { //收集依赖的函数
    if (!activeEffect) return
    let depsMap = targetMap.get(target)
    if(!depsMap) {
        targetMap.set(target, (depsMap = new Map()))
    }
    let dep = depsMap.get(key)
    if(!dep) {
        depsMap.set(key, (dep = new Set()))
    }
    dep.add(activeEffect)
}

export function trigger(target, key) {//触发更新
    const depsMap = targetMap.get(target); // 找到target对象对应的集合
    if (!depsMap) return;
    const dep = depsMap.get(key) //找到key对应的dep集合
    if(dep) {//执行每个依赖于key（响应式对象的值）值函数
        dep.forEach(effect => effect())
    }
}

export function ref(raw) {
    // 判断raw是否是ref创建的对象，如果是的话直接返回
    if (isObject(raw) && raw.__v_isRef)return
  
    let value = convert(raw)
    const r = {
      __v_isRef: true,
      get value () {
        track(r, 'value')
        return value
      },
      set value (newValue) {
        if(newValue !== value) {
          raw = newValue
          value = convert(raw)
          trigger(r, 'value')
        }
      }
    }
    return r
  }

  export function toRefs (proxy) {
    //如果是数组我们创建一个新的数组 否则返回空对象
    const ret = proxy instanceof Array ? new Array(proxy.length) : {}
  
    for (const key in proxy) {
        //将每一项转换为类似ref的对象
      ret[key] = toProxyRef(proxy, key)
    }
  
    return ret
  }

  function toProxyRef (proxy, key) {
    const r = {
      __v_isRef: true,
      get value () {
        return proxy[key]//这里不收集依赖是因为proxy是响应式对象，当我们访问响应式对象属性会触发get方法自动收集依赖
      },
      set value (newValue) {
        proxy[key] = newValue//这里不需要触发更新是因为proxy是响应式对象，当我们重新赋值会触发响应式对象的set方法触发更新
      }
    }
    return r
  }

  
export function computed (getter) {
    const result = ref() //不传 value救赎undefined
  
    effect(() => (result.value = getter()))
  
    return result
  }